home *** CD-ROM | disk | FTP | other *** search
/ BCI NET 2 / BCI NET 2.iso / archives / programming / source / xdme_1.84_src.lha / XDME / Src / block.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-10  |  39.2 KB  |  1,684 lines

  1. /******************************************************************************
  2.  
  3.     MODUL
  4.     $Id: block.c 1.3 1994/09/09 12:31:30 digulla Exp digulla $
  5.  
  6.     DESCRIPTION
  7.     In this module are all functions that work with blocks.
  8.  
  9.     NOTES
  10.     - A block has these attributes:
  11.         1- the editor it is in
  12.         2- the type (BT_NONE, BT_LINE, BT_NORMAL or BT_VERTICAL)
  13.            if it is BT_NONE, there is no block.
  14.         3- a start-position (line/column). If the type is not BT_NONE,
  15.            this field is guranteed to contain a valid position.
  16.         4- an end-position. If the line is -1, the end-position is not
  17.            yet defined.
  18.  
  19.     $Log: block.c $
  20.  * Revision 1.3  1994/09/09  12:31:30  digulla
  21.  * added new style Prototypes, DEFCMD and DEFHELP
  22.  * added function IsBlockVisible()
  23.  *
  24.  * Revision 1.2  1994/08/30  11:06:14  digulla
  25.  * added some parentheses for GCC
  26.  *
  27.  * Revision 1.1  1994/08/14  12:28:34  digulla
  28.  * Initial revision
  29.  *
  30.  
  31. ******************************************************************************/
  32.  
  33.  
  34. /**************************************
  35.         Includes
  36. **************************************/
  37. #define BLOCK_C  1
  38. #include <defs.h>
  39. #include "clipboard.h"
  40. #define MYDEBUG     0
  41. #include "debug.h"
  42.  
  43.  
  44. /**************************************
  45.         Globale Variable
  46. **************************************/
  47.  
  48.  
  49. /**************************************
  50.       Interne Defines & Strukturen
  51. **************************************/
  52. #define SWAP(a,b)   (void)((a)^=(b),(b)^=(a),(a)^=(b))
  53. #define MIN(a,b)    ((a) <= (b) ? (a) : (b))
  54. #define MAX(a,b)    ((a) >= (b) ? (a) : (b))
  55.  
  56. /**************************************
  57.         Interne Variable
  58. **************************************/
  59. /* ADA 8.8.94 static entfernt, weil win:format_string() block_type braucht */
  60. UWORD block_type = BT_LINE;    /* default-type of block */
  61.  
  62.  
  63. /******************************************
  64.  
  65.   NOTE: ActualBlock is const so that its fields cannot be
  66.   changed from other files except through the interface
  67.   functions provided.  This is so that certain consistancies
  68.   about the block can be maintained.
  69.  
  70. *******************************************/
  71. Prototype NOT_BLOCK_C_CONST Block     ActualBlock;
  72.  
  73. Block ActualBlock =
  74. {
  75.     NULL,        /* ED * ep;                */
  76.     BT_NONE,        /* UWORD type;               */
  77.     0,            /* UWORD flags;               */
  78.     -1, -1,        /* Line start_line, end_line       */
  79.     -1, -1,        /* Column start_column, end_column */
  80.     {            /* col[3][2]               */
  81.     {-1, -1},
  82.     {-1, -1},
  83.     {-1, -1}
  84.     }
  85. };
  86.  
  87. Prototype ED * set_block_ep (ED * new_ed);
  88.  
  89. ED * set_block_ep (ED * new_ep)
  90. {
  91.     ActualBlock.ep = new_ep;
  92.  
  93.     block_normalize ();
  94.  
  95.     return new_ep;
  96. } /* set_block_ep */
  97.  
  98.  
  99. Prototype UWORD set_block_type (UWORD type);
  100.  
  101. UWORD set_block_type (UWORD type)
  102. {
  103.     /* check if there is a block and convert the type */
  104.     if (ActualBlock.type != type)
  105.     {
  106.     /* set new type */
  107.     ActualBlock.type = type;
  108.     block_normalize ();
  109.     }
  110.  
  111.     if (type == BT_NONE)
  112.     {
  113.     ActualBlock.ep = NULL;
  114.     ActualBlock.flags = 0;
  115.     }
  116.  
  117.     return type;
  118. } /* set_block_type */
  119.  
  120.  
  121. Prototype UWORD set_block_flags (UWORD newflags, UWORD flagmask);
  122.  
  123. UWORD set_block_flags (UWORD newflags, UWORD flagmask)
  124. {
  125.     return ActualBlock.flags = (ActualBlock.flags & ~flagmask) |
  126.                    (newflags          &  flagmask);
  127. } /* set_block_flags */
  128.  
  129.  
  130. static void reset_block_set_flags (void)
  131. {
  132.    set_block_flags ( ( ActualBlock.start_line   >= 0 &&
  133.                ActualBlock.start_column >= 0
  134.              )? BF_START_SET:0, BF_START_SET    );
  135.  
  136.    set_block_flags ( ( ActualBlock.end_line   >= 0 &&
  137.                ActualBlock.end_column >= 0
  138.              )? BF_END_SET:0, BF_END_SET    );
  139. } /* reset_block_set_flags */
  140.  
  141. static void unswap_block_ends (void)
  142. {
  143.     if (ActualBlock.flags & BF_LINE_SWAPPED)
  144.     SWAP (ActualBlock.start_line, ActualBlock.end_line);
  145.  
  146.     if (ActualBlock.flags & BF_COLUMN_SWAPPED)
  147.     SWAP (ActualBlock.start_column, ActualBlock.end_column);
  148.  
  149.     set_block_flags (0, BF_SWAPPED_MASK );
  150.     reset_block_set_flags ();
  151. } /* unswap_block_ends */
  152.  
  153.  
  154. static void swap_block_ends (void)
  155. {
  156.   if ((ActualBlock.flags & BF_SET_MASK) == BF_SET_MASK )
  157.     {
  158.       if (ActualBlock.start_line > ActualBlock.end_line &&
  159.       (ActualBlock.flags & BF_SWAPPED_MASK) == 0       )
  160.     {
  161.       SWAP (ActualBlock.start_line,   ActualBlock.end_line);
  162.       SWAP (ActualBlock.start_column, ActualBlock.end_column);
  163.       set_block_flags (BF_SWAPPED_MASK, BF_SWAPPED_MASK);
  164.     }
  165.       else if (ActualBlock.start_line == ActualBlock.end_line &&
  166.            ActualBlock.start_column > ActualBlock.end_column &&
  167.            (ActualBlock.flags & BF_COLUMN_SWAPPED) == 0         )
  168.     {
  169.       SWAP (ActualBlock.start_column, ActualBlock.end_column);
  170.       set_block_flags (BF_SWAPPED_MASK, BF_SWAPPED_MASK);
  171.     }
  172.     }
  173.     reset_block_set_flags ();
  174. } /* swap_block_ends */
  175.  
  176. Prototype Block * get_block (Block * buf);
  177.  
  178. Block * get_block (Block * buf)
  179. {
  180.     if (buf)
  181.     memcpy (buf, &ActualBlock, sizeof(Block));
  182.  
  183.     return buf;
  184. } /* get_block */
  185.  
  186.  
  187. Prototype Block * set_block (Block *buf);
  188.  
  189. Block * set_block (Block * buf)
  190. {
  191.     if (buf)
  192.     {
  193.     memcpy (&ActualBlock, buf, sizeof (Block));
  194.     swap_block_ends ();
  195.     block_normalize ();
  196.     }
  197.  
  198.     return buf;
  199. } /* set_block */
  200.  
  201.  
  202.  
  203. Prototype void set_block_start (Line line, Column column);
  204.  
  205. void set_block_start (Line line, Column column)
  206. {
  207.     unswap_block_ends ();
  208.  
  209.     if (line != -2) /* -2 means leave  alone */
  210.     ActualBlock.start_line     = line;
  211.     if (column != -2)
  212.     ActualBlock.start_column = column;
  213.  
  214.     if (ActualBlock.start_line >= 0 &&
  215.     ActualBlock.start_column >= 0 )
  216.     set_block_flags (BF_START_SET, BF_START_SET);
  217.       else
  218.     set_block_flags (0, BF_START_SET);
  219.  
  220.     swap_block_ends ();
  221.  
  222.     block_normalize ();
  223. } /* set_block_start */
  224.  
  225.  
  226. Prototype void set_block_end (Line line, Column column);
  227.  
  228. void set_block_end (Line line, Column column)
  229. {
  230.     unswap_block_ends();
  231.  
  232.     if (line != -2) /* -2 means leave  alone */
  233.     ActualBlock.end_line   = line;
  234.     if (column != -2)
  235.     ActualBlock.end_column = column;
  236.  
  237.     if (ActualBlock.end_line >= 0 &&
  238.     ActualBlock.end_column >= 0 )
  239.     set_block_flags (BF_END_SET, BF_END_SET);
  240.       else
  241.     set_block_flags (0, BF_END_SET);
  242.  
  243.     swap_block_ends();
  244.  
  245.     block_normalize();
  246. } /* set_block_end */
  247.  
  248.  
  249. Prototype void unblock (void);
  250.  
  251. void unblock (void)
  252. {
  253.     ActualBlock.ep   = NULL;
  254.     ActualBlock.type = BT_NONE;
  255.     ActualBlock.flags= 0;
  256.  
  257.     ActualBlock.start_line   =
  258.     ActualBlock.start_column =
  259.     ActualBlock.end_line     =
  260.     ActualBlock.end_column   = -1;
  261.  
  262.     block_normalize();
  263. } /* unblock */
  264.  
  265. /*****************************************************************************
  266.  
  267.     NAME
  268.     block_leftcolumn
  269.     block_rightcolumn
  270.  
  271.     PARAMETER
  272.     Line line  The line number of the line in question.
  273.  
  274.     RETURN
  275.     The column number for the left or right edge of the block
  276.     on a given line.
  277.  
  278.     DESCRIPTION
  279.      These functions examine the ActualBlock structure and
  280.     determine where the left or right edges of the block
  281.     extend for a given line.  Note that the edge of the block
  282.     may be past any actual text on that line.  Note also that
  283.     the line number is understood to be a line in the
  284.     ActualBlock.ep editor and not the current editor.
  285.  
  286.     The returned value is only valid after a call to
  287.     normalize_block().
  288.  
  289.     EXAMPLE
  290.  
  291. ******************************************************************************/
  292. Prototype Column block_leftcolumn (Line);
  293.  
  294. Column block_leftcolumn (Line line)
  295. {
  296.     if (block_ok ())
  297.     {
  298.     if (line == ActualBlock.start_line)
  299.         return ActualBlock.col[0][0];
  300.  
  301.     if (    line >  ActualBlock.start_line &&
  302.         line <    ActualBlock.end_line)
  303.         return ActualBlock.col[1][0];
  304.  
  305.     if (line == ActualBlock.end_line)
  306.         return ActualBlock.col[2][0];
  307.     }
  308.  
  309.     return -1;
  310. } /* block_leftcolumn */
  311.  
  312.  
  313. Prototype Column block_rightcolumn (Line);
  314.  
  315. Column block_rightcolumn (Line line)
  316. {
  317.     if (block_ok ())
  318.     {
  319.     if (line == ActualBlock.start_line)
  320.         return ActualBlock.col[0][1];
  321.  
  322.     if (    line >  ActualBlock.start_line &&
  323.         line <    ActualBlock.end_line)
  324.         return ActualBlock.col[1][1];
  325.  
  326.     if (line == ActualBlock.end_line)
  327.         return ActualBlock.col[2][1];
  328.     }
  329.  
  330.     return -1;
  331. } /* block_rightcolumn */
  332.  
  333.  
  334. /*****************************************************************************
  335.  
  336.     NAME
  337.     block_normalize
  338.  
  339.     PARAMETER
  340.     none
  341.  
  342.     RETURN
  343.     void
  344.  
  345.     DESCRIPTION
  346.     This function initializes the col matrix of ActualBlock.
  347.     The matrix holds the left and right column positions for
  348.     the three cases of lines we have to consider for a block:
  349.     the first line, the middle line(s), and the last line.
  350.  
  351.     EXAMPLE
  352.  
  353. ******************************************************************************/
  354. Prototype void block_normalize (void);
  355.  
  356. void block_normalize (void)
  357. {
  358.     Column left, right;
  359.  
  360.     if ((ActualBlock.flags & BF_SET_MASK ) == BF_SET_MASK)
  361.     {
  362.     switch (ActualBlock.type)
  363.     {
  364.     case BT_LINE:
  365.         ActualBlock.col[0][0] =
  366.         ActualBlock.col[1][0] =
  367.         ActualBlock.col[2][0] = 0;
  368.  
  369.         ActualBlock.col[0][1] =
  370.         ActualBlock.col[1][1] =
  371.         ActualBlock.col[2][1] = MAXLINELEN;
  372.  
  373.         break;
  374.  
  375.     case BT_NORMAL:
  376.         left  = ActualBlock.start_column;
  377.         right = ActualBlock.end_column;
  378.  
  379.         ActualBlock.col[0][0] = left;
  380.         ActualBlock.col[1][0] =
  381.         ActualBlock.col[2][0] = ActualBlock.start_line ==
  382.                     ActualBlock.end_line ? left : 0;
  383.  
  384.         ActualBlock.col[0][1] =
  385.         ActualBlock.col[1][1] = ActualBlock.start_line ==
  386.                     ActualBlock.end_line ? right : MAXLINELEN;
  387.         ActualBlock.col[2][1] = right;
  388.  
  389.         break;
  390.  
  391.     case BT_VERTICAL:
  392.     case BT_HORIZONTAL:
  393.         left  = MIN (ActualBlock.start_column, ActualBlock.end_column);
  394.         right = MAX (ActualBlock.start_column, ActualBlock.end_column);
  395.  
  396.         ActualBlock.col[0][0] =
  397.         ActualBlock.col[1][0] =
  398.         ActualBlock.col[2][0] = left;
  399.  
  400.         ActualBlock.col[0][1] =
  401.         ActualBlock.col[1][1] =
  402.         ActualBlock.col[2][1] = right;
  403.  
  404.         break;
  405.  
  406.     default:
  407.         ActualBlock.col[0][0] =
  408.         ActualBlock.col[1][0] =
  409.         ActualBlock.col[2][0] =
  410.         ActualBlock.col[0][1] =
  411.         ActualBlock.col[1][1] =
  412.         ActualBlock.col[2][1] = -1;
  413.  
  414.         break;
  415.     } /* switch (ActualBlock.type) */
  416.     }
  417.     else
  418.     {
  419.      ActualBlock.col[0][0] =
  420.      ActualBlock.col[1][0] =
  421.      ActualBlock.col[2][0] =
  422.      ActualBlock.col[0][1] =
  423.      ActualBlock.col[1][1] =
  424.      ActualBlock.col[2][1] = -1;
  425.     }
  426.  
  427. } /* block_normalize */
  428.  
  429.  
  430. /*****************************************************************************
  431.  
  432.     NAME
  433.     is_inblock
  434.  
  435.     PARAMETER
  436.     Line   line;        The line we want to check
  437.     Column column;        the column we are in. If column == -1,
  438.                 we just check the line.
  439.  
  440.     RETURN
  441.     UWORD blockpos;    Flags:
  442.  
  443.     BP_OUTSIDE    we are not inside any block.
  444.     BP_START    we are in the line where the block starts.
  445.     BP_END        we are in the line where the block ends.
  446.     BP_BESIDE    the line contains some portion of the block.
  447.             Could be left or right of the block body.
  448.     BP_INSIDE    the char is inside the block.  BP_INSIDE
  449.             always implies BP_BESIDE (can't be in a block
  450.             unless there is some block on the line).
  451.  
  452.     DESCRIPTION
  453.     This function checks whether a position is inside a block.
  454.     If it isn't, we get BP_OUTSIDE (= 0).  If the indicated
  455.     line contains some portion of a block, we get BP_BESIDE.
  456.     If the indicated column is in the block, we get
  457.     BP_BESIDE|BP_INSIDE.
  458.  
  459.     Note that the block type has no bearing on these results.
  460.     We treat all blocks the same way regardless of type. Also
  461.     note that some portion of a block may not actually have
  462.     characters in it.  A HORIZONTAL block may extend over a
  463.     blank line, for example.
  464.  
  465.     If line is the start-line of the block, BP_START is set.
  466.     If line is the last line of the block, BP_END is set.
  467.  
  468.     If we don't care about the column, we may simply specify
  469.     -1L for column. Else, we give the column we want to check
  470.     and get an additional BP_INSIDE if we are really inside
  471.     the block.
  472.  
  473.     EXAMPLE
  474.  
  475.     BP_OUTSIDE    there is no block in that line
  476.  
  477.     BP_BESIDE    there is some part of the block on this line, but
  478.             this is not the start or end line.  Also we are
  479.             either not within the highlighted area (or we
  480.             specified -1 for column).
  481.  
  482.     BP_START|BP_BESIDE
  483.             the line is the start-line of the block. Also the
  484.             block has more than one line since BP_END is not
  485.             set. The block is not a line-block (BP_INSIDE is
  486.             always true for line-blocks !).
  487.  
  488.     BP_START|BP_END|BP_BESIDE
  489.             The block has only one line and we are in it. This is
  490.             also no line-block.
  491.  
  492.     BP_START|BP_INSIDE|BP_BESIDE
  493.             We are inside the block and on it's start-line.
  494.  
  495.     BP_INSIDE|BP_BESIDE
  496.             this position is inside the block, but not in the
  497.             start- nor in the end-line.
  498.  
  499. ******************************************************************************/
  500.  
  501. Prototype UWORD is_inblock (Line line, Column col);
  502.  
  503. UWORD is_inblock (Line line, Column col)
  504. {
  505.     UWORD blockpos = BP_OUTSIDE;
  506.  
  507.     /* Look if there is a block, the actual editor is the one that
  508.        has it, we are not in a commandline and the line is inside it.
  509.        NOTE: if there is no end-line yet, the last condition can never
  510.        be TRUE ! */
  511.  
  512.     if (    ActualBlock.type != BT_NONE     &&
  513.         Ep == ActualBlock.ep        &&
  514.         !GETF_COMLINEMODE(Ep)           &&
  515.         line >= ActualBlock.start_line  &&
  516.         line <= ActualBlock.end_line    &&
  517.         (ActualBlock.flags & BF_SET_MASK) == BF_SET_MASK)
  518.     {
  519.  
  520.     blockpos |= BP_BESIDE;    /* some part of block is on this line */
  521.  
  522.     /* Check for start- and end-line */
  523.  
  524.     if (line == ActualBlock.start_line)
  525.         blockpos |= BP_START;
  526.  
  527.     if (line == ActualBlock.end_line)
  528.         blockpos |= BP_END;
  529.  
  530.     /* now check, if we are inside the block */
  531.  
  532.     if ( block_leftcolumn( line) <= col &&
  533.          block_rightcolumn(line) >= col   )
  534.         blockpos |= BP_INSIDE;
  535.  
  536.     } /* if validblock */
  537.  
  538.     /* return the flags */
  539.  
  540.     return (blockpos);
  541. } /* is_inblock */
  542.  
  543.  
  544. /*****************************************************************************
  545.  
  546.     NAME
  547.     IsBlockVisible
  548.  
  549.     PARAMETER
  550.     -
  551.  
  552.     RETURN
  553.     BOOL yes;
  554.  
  555.     DESCRIPTION
  556.     Returns TRUE if the currently marked block is visible at least
  557.     partially.
  558.  
  559. ******************************************************************************/
  560.  
  561. Prototype BOOL IsBlockVisible (void);
  562.  
  563. BOOL IsBlockVisible (void)
  564. {
  565.     return (BOOL) (block_ok () && ActualBlock.ep == Ep &&
  566.         !(ActualBlock.start_line >= Ep->topline + Lines ||
  567.         ActualBlock.end_line < Ep->topline));
  568. } /* IsBlockVisible */
  569.  
  570.  
  571. /*****************************************************************************
  572.  
  573.     NAME
  574.     displayblock
  575.  
  576.     PARAMETER
  577.     BOOL on;    Shall we turn the block on ?
  578.  
  579.     RETURN
  580.     void
  581.  
  582.     DESCRIPTION
  583.     This function displays the block. If on is TRUE, the block
  584.     is drawn (again), else we turn the block off. In this case, the
  585.     block-selection is lost !
  586.  
  587. ******************************************************************************/
  588.  
  589. Prototype void displayblock (BOOL on);
  590.  
  591. void displayblock (BOOL on)
  592. {
  593.  
  594.     if (on)
  595.     {
  596.  
  597.     /* draw block and write the text over it */
  598.     redraw_block (TRUE,
  599.             Ep->topline, Ep->topcolumn,
  600.             Ep->topline + Lines - 1, Ep->topcolumn + Columns - 1);
  601.  
  602.     } else if (block_ok ()) /* turn block off AND there was a block */
  603.     {
  604.     ED  * ep    = Ep;
  605.     RP  * rp    = ep->win->RPort;
  606.     UWORD start = ActualBlock.start_line;
  607.     UWORD end   = ActualBlock.end_line;
  608.  
  609.     /* no block anymore */
  610.     unblock ();
  611.  
  612.     /* block is not visible */
  613.     if (end < ep->topline)
  614.         return;
  615.  
  616.     /* start-line: If block starts above the 1st visible line,
  617.        we start in line 0 else in the line where the block starts. */
  618.  
  619.     if (start < ep->topline)
  620.         start = ep->topline;
  621.  
  622.     /* is end-line visible ? */
  623.     if (ep->topline + Lines < end)
  624.         end = ep->topline + Lines -1;
  625.  
  626.     if (start <= end)
  627.     {
  628.         /* color and mask */
  629.  
  630.         SetAPen (rp, TEXT_BPEN(ep));
  631.         SetWrMsk (rp, BLOCK_MASK(ep));
  632.  
  633.         /* clear area */
  634.         RectFill (rp, Xbase, ROW(start - Ep->topline), Xpixs,
  635.             ROW(end-Ep->topline + 1)-1);
  636.  
  637.         /* redraw text */
  638.         redraw_block (TRUE, start, ep->topcolumn,
  639.         end, ep->topcolumn + Columns -1);
  640.     }
  641.     } else /* just say "there is no block" */
  642.     unblock ();
  643.  
  644. } /* displayblock */
  645.  
  646.  
  647. /*****************************************************************************
  648.  
  649.     NAME
  650.     do_blocktype
  651.  
  652.     PARAMETER
  653.     av[0] : blocktype
  654.     av[1] : LINE/CHARACTER/NORMAL/HORIZONTAL/VERTICAL
  655.  
  656.     RETURN
  657.     void
  658.  
  659.     DESCRIPTION
  660.     This sets the type of block you want to use. Allowed are 3 types
  661.     of blocks:
  662.  
  663.         LINE:    The line-block begins in a line and ends in a line.
  664.             The columns are ignored and both lines are included
  665.             in the block.
  666.         CHARCTER or NORMAL: The character-block begins at a specifiy line
  667.             and columns and ends at another character-position.
  668.         HORIZONTAL: The horizontal block is a rectangular region of text
  669.             like a cell of a table or a comment to the left or
  670.             right of source code.
  671.         VERTICAL:    The vertical block is a rectangular region of text
  672.             like a column of a table.
  673.  
  674.     If you have already marked a block, it is converted to the new type.
  675.  
  676. ******************************************************************************/
  677.  
  678. /*DEFHELP #cmd prefs,block BLOCKTYPE type - @{B}type@{UB} is LINE (old), CHARACTER (like everywhere else) or VERTICAL (rectangular block). */
  679.  
  680. DEFUSERCMD("blocktype", 1, CF_VWM, void, do_blocktype, (void),)
  681. {
  682.     switch (av[1][0])
  683.     {
  684.     case 'l':
  685.     case 'L':
  686.     block_type = BT_LINE;
  687.     break;
  688.  
  689.     case 'c':
  690.     case 'C':
  691.     case 'n':
  692.     case 'N':
  693.     block_type = BT_NORMAL;
  694.     break;
  695.  
  696.     case 'v':
  697.     case 'V':
  698.     block_type = BT_VERTICAL;
  699.     break;
  700.  
  701.     case 'h':
  702.     case 'H':
  703.     block_type = BT_HORIZONTAL;
  704.     break;
  705.  
  706.     default:
  707.     error ("block:\nUnknown block type.");
  708.     return;
  709.     break;
  710.     }
  711.  
  712.     set_block_type( block_type );
  713.  
  714.     if (block_ok() )
  715.       /* clean screen and force redraw */
  716.       text_redisplay ();
  717.  
  718. } /* do_blocktype */
  719.  
  720.  
  721. /*****************************************************************************
  722.  
  723.     NAME
  724.     do_block_prep
  725.  
  726.     PARAMETER
  727.     none
  728.  
  729.     RETURN
  730.     BOOL TRUE if ActualBlock.ep is current editor AND .type is block_type.
  731.          FALSE otherwise.
  732.  
  733.     DESCRIPTION
  734.     This routine does some clean-up in preparation for some of the
  735.     do_block functions, in particular block, bstart, bend, and lineblock.
  736.     If it returns FALSE, those operations should not be completed.
  737.  
  738. ******************************************************************************/
  739.  
  740. static BOOL do_block_prep (void)
  741. {
  742.     ED * ep = Ep;
  743.  
  744.     if (block_ok ())
  745.     {
  746.       if (ActualBlock.ep != ep)
  747.       {
  748.     if (GETF_AUTOUNBLOCK(ep))
  749.     {
  750.       if (!GETF_ICONMODE(ActualBlock.ep))
  751.       {
  752.         /* change editor */
  753.         switch_ed (ActualBlock.ep);
  754.  
  755.         /* switch block off */
  756.         text_redrawblock (0);
  757.  
  758.         /* come back */
  759.         switch_ed (ep);
  760.       } else  /* block_ok, AB.ep != ep, autounblock, iconmode */
  761.       {
  762.         unblock ();
  763.       }
  764.     } else    /* block_ok, AB.ep != ep, !autounblock */
  765.     {
  766.       error ("Block\nBlock already marked");
  767.       return FALSE;
  768.     }
  769.       }
  770.     } else /* !block_ok */
  771.     {
  772.       if (ActualBlock.ep != ep) /* treat as if autounblock if !block_ok */
  773.     unblock ();
  774.     }
  775.     set_block_ep (ep);
  776.     set_block_type (block_type);
  777.     return TRUE;
  778. } /* do_block_prep */
  779.  
  780. /*****************************************************************************
  781.  
  782.     NAME
  783.     do_block
  784.  
  785.     PARAMETER
  786.     av[0] : block unblock bstart bend lineblock
  787.  
  788.     RETURN
  789.     void
  790.  
  791.     DESCRIPTION
  792.     This routine allows to specify the limits of a block.
  793.  
  794.     The two commands BSTART and BEND can be used anywhere in the
  795.     text (ie. you can user BEND above a BSTART). In this case,
  796.     BEND and BSTART swap their meanings, ie. BEND now sets the start
  797.     of the block and BSTART the end. This is for specifying a block
  798.     with the mouse. If you drag the mouse above the BSTART, the BEND
  799.     will begin to set the beginning of the block and if you drag it
  800.     down over the end of the block, BEND will switch back.
  801.  
  802. ******************************************************************************/
  803.  
  804. /*DEFHELP #cmd block BLOCK - Set start or end (if start is already set) of block */
  805. /*DEFHELP #cmd block BSTART - Set start of block */
  806. /*DEFHELP #cmd block BEND - Set end of block */
  807. /*DEFHELP #cmd block UNBLOCK - clear the block markers for the current window */
  808. /*DEFHELP #cmd block LINEBLOCK - mark the current line */
  809.  
  810. DEFUSERCMD("block",     0, CF_VWM, void, do_block, (void),;)
  811. DEFUSERCMD("bstart",    0, CF_VWM, void, do_block, (void),;)
  812. DEFUSERCMD("bend",      0, CF_VWM, void, do_block, (void),;)
  813. DEFUSERCMD("unblock",   0, CF_VWM, void, do_block, (void),;)
  814. DEFUSERCMD("lineblock", 0, CF_VWM, void, do_block, (void),)
  815. {
  816.     ED * ep = Ep;
  817.  
  818.     /* make sure we work on the most recent version of the text */
  819.  
  820.     text_sync ();
  821.  
  822.     /* look for the 1st character */
  823.  
  824.     switch(av[0][0])
  825.     {
  826.     case 'b': /* Block Bstart Bend */
  827.         switch (av[0][1]) /* b[lse] */
  828.         {
  829.         case 'l': /* BLock */
  830.             if (do_block_prep ())
  831.             {
  832.               switch ( ActualBlock.flags & BF_SET_MASK )
  833.               {
  834.             case BF_START_SET|BF_END_SET : /* unblock and set start */
  835.               if (GETF_AUTOUNBLOCK(ep))
  836.               {
  837.                   /* turn block off */
  838.                   text_redrawblock (0);
  839.                   set_block_ep (ep);
  840.                   set_block_type (block_type);
  841.               } else
  842.               {
  843.                   /* no auto-unblock ? ERROR ! */
  844.                   error ("block:\nBlock already marked");
  845.                   break;
  846.               } /* autounblock */
  847.               /* Fall through to next case */
  848.             case 0: /* neither end set, so we set the start line */
  849.             case BF_END_SET : /* We need to set the end */
  850.               set_block_start (ep->line, ep->column);
  851.               title ("Block begin");
  852.               break;
  853.             case BF_START_SET : /* We need to set the end */
  854.               set_block_end (ep->line, ep->column);
  855.               title ("Block end");
  856.               break;
  857.               }
  858.               if (block_ok ())
  859.             text_redrawblock (1);
  860.             }
  861.         break;
  862.         case 's': /* BStart */
  863.             if (do_block_prep ())
  864.             {
  865.               if (block_ok ())
  866.               {
  867.             redraw_block (FALSE, ep->line, ep->column, -1, -1);
  868.               } else
  869.               {
  870.             set_block_start (ep->line, ep->column);
  871.             if (block_ok ())
  872.               text_redrawblock (1);
  873.               }
  874.               title ("Block start");
  875.             }
  876.         break;
  877.  
  878.         case 'e': /* BEnd */
  879.             if (do_block_prep ())
  880.             {
  881.               if (block_ok ())
  882.               {
  883.             redraw_block (FALSE, -1, -1, ep->line, ep->column);
  884.               } else
  885.               {
  886.             set_block_end (ep->line, ep->column);
  887.             if (block_ok ())
  888.               text_redrawblock (1);
  889.               }
  890.               title ("Block end");
  891.             }
  892.         break;
  893.         }
  894.     break;
  895.  
  896.     case 'u':
  897.         /* force UNDRAW and say what we did */
  898.  
  899.         text_redrawblock (0);
  900.  
  901.         title ("Block unmarked");
  902.     break;
  903.  
  904.     case 'l':
  905.         /* mark the whole line as a block */
  906.  
  907.         if (do_block_prep ())
  908.         {
  909.           if (block_ok ())
  910.           {
  911.         text_redrawblock (0);
  912.           }
  913.           unblock ();
  914.           set_block_ep (ep);
  915.           set_block_type (BT_LINE);
  916.           set_block_start (ep->line, 0);
  917.           set_block_end (ep->line, MAXLINELEN);
  918.           title ("Line marked");
  919.  
  920.           /* force redraw */
  921.  
  922.           text_redrawblock (1);
  923.         }
  924.     break;
  925.     }
  926. } /* do_block */
  927.  
  928.  
  929. /*****************************************************************************
  930.  
  931.     NAME
  932.     block_ok
  933.  
  934.     PARAMETER
  935.     void
  936.  
  937.     RETURN
  938.     BOOL
  939.  
  940.     DESCRIPTION
  941.     Returns TRUE, if there is a valid block.
  942.  
  943. ******************************************************************************/
  944.  
  945. Prototype BOOL block_ok (void);
  946.  
  947. BOOL block_ok (void)
  948. {
  949.     /* A block is valid IF it has a type AND both ends are valid */
  950.  
  951.     return ((BOOL)(ActualBlock.type != BT_NONE &&
  952.           (ActualBlock.flags & BF_SET_MASK) == BF_SET_MASK));
  953. } /* block_ok */
  954.  
  955. /*DEFHELP #cmd block,clip COPY - copy currently marked text into clipboard */
  956.  
  957. DEFUSERCMD("copy", 0, CF_VWM|CF_ICO|CF_COK, void, do_copy, (void),)
  958. {
  959.     struct IOClipReq * ior;
  960.     char * str = block_to_string ();
  961.  
  962.     if (str)
  963.     {
  964.     D(bug("block_to_string:\n`%s'\n", str));
  965.  
  966.     if ((ior = CBOpen (0)))
  967.     {
  968.         CBWriteFTXT (ior, str);
  969.  
  970.         CBClose (ior);
  971.     }
  972.  
  973.     free (str);
  974.     }
  975.     else
  976.     D(bug("block_to_string: (NUL)\n"));
  977. } /* do_copy */
  978.  
  979.  
  980. /*****************************************************************************
  981.  
  982.     NAME
  983.     block_to_string
  984.  
  985.     PARAMETER
  986.     void
  987.  
  988.     RETURN
  989.     char * string;
  990.  
  991.     DESCRIPTION
  992.     Creates a string from the currently marked block. The lines
  993.     are separated with '\n' and the string is terminated with
  994.     '\0'.
  995.  
  996.     NOTES
  997.     - The string will only contain '\n's, if the end of a line is
  998.       included in the block.
  999.     - The block has to be freed with free() if you don't need it anymore,
  1000.       but this may change.
  1001.  
  1002.     HISTORY
  1003.     13. Feb 1993    ada created
  1004.  
  1005. ******************************************************************************/
  1006.  
  1007.  
  1008. Prototype char * block_to_string (void);
  1009.  
  1010. char * block_to_string (void)
  1011. {
  1012.     ED     * ep;
  1013.     Line   line;
  1014.     int    length;
  1015.     int    linelen;
  1016.     char * string,
  1017.      * ptr,
  1018.      * text;
  1019.  
  1020.     if (block_ok ())
  1021.     {
  1022.     ep = ActualBlock.ep;
  1023.  
  1024.     /* to prevent us from writing the same code twice (once for
  1025.        figuring out how long the string will be and once for actually
  1026.        filling the string), we simply check if "string" is NULL.
  1027.        If it is, we have to get the length; else we copy the contents. */
  1028.  
  1029.     ptr = string = NULL;
  1030.  
  1031.     /*
  1032.        LINE: The length of the block is the sum of the lengths of all
  1033.         lines + CR + \0.
  1034.  
  1035.        NORMAL: The length of this block is the sum of the lengths of all
  1036.         body lines plus the length of the start- and the end-line
  1037.         plus \0. The length of the start-line is
  1038.  
  1039.             o 1, if length < start_column
  1040.             o length-start_column+1, if length > start_column
  1041.  
  1042.         and the length of the end-line is
  1043.  
  1044.             o end_column+1, if length > end_column
  1045.             o length+1, if length < end_column
  1046.  
  1047.         If the block has only one line, the length is
  1048.  
  1049.             o end_column-start_column if length > end_col
  1050.             o length-start_column+1 if length < end_col
  1051.  
  1052.        VERTICAL: The length of the block is the sum of the lengths of
  1053.         all lines + CR + \0. The length of a line is
  1054.  
  1055.             o 0 if the line is < start-column
  1056.             o length-start_column if the line is < end-column
  1057.             o start_column-end_column if line is >= end-column
  1058.  
  1059.        When we have the length, we allocate memory for it and copy
  1060.        the block into that memory.
  1061.      */
  1062.  
  1063.     length = 1;    /* ending '\0' */
  1064.  
  1065.     text_sync ();   /* use latest text */
  1066.  
  1067.     do {
  1068.         for (line=ActualBlock.start_line; line <= ActualBlock.end_line;
  1069.                                        line ++)
  1070.         {
  1071.         Column left, right;
  1072.  
  1073.         text = GETTEXT (ep,line);
  1074.         linelen = strlen (text);
  1075.  
  1076.         if (linelen >= MAXLINELEN)
  1077.         {
  1078.             D(bug("block_to_string: Aborting..."
  1079.                 "len (%ld) in line %ld too large !\n",
  1080.                 linelen, line));
  1081.             break;
  1082.         }
  1083.  
  1084.         if (string && ptr-string > length)
  1085.             break;
  1086.  
  1087.         left  = block_leftcolumn( line );
  1088.         right = block_rightcolumn( line );
  1089.  
  1090.         if ( string )
  1091.             {
  1092.               if ( left < linelen )
  1093.             {
  1094.                strncpy( ptr, &text[left], right - left + 1 );
  1095.                ptr += MIN( right - left + 1, linelen - left );
  1096.             }
  1097.               *ptr ++ = '\n';
  1098.             }
  1099.           else
  1100.             {
  1101.               if ( left < linelen )
  1102.               length += MIN( right - left + 1, linelen - left + 1 );
  1103.             else
  1104.               length += 1;
  1105.             }
  1106.  
  1107.         }
  1108.  
  1109.         if (string && ptr-string > length)
  1110.         {
  1111.         D(bug("Aborting ... String exceeds "
  1112.               "(%ld:%ld) )buffer in line %ld !\n",
  1113.             ptr-string, length, line));
  1114.         }
  1115.  
  1116.         if (string)
  1117.         break;    /* done ! */
  1118.         else
  1119.         {
  1120.         string = malloc (length+256);   /* allocate memory */
  1121.         ptr = string;            /* points to EOS */
  1122.         }
  1123.  
  1124.     /* after the loop, the string must be non-NULL, else we didn't get the
  1125.        memory ! */
  1126.     } while (string != NULL);
  1127.  
  1128.     if (string) /* add '\0' */
  1129.     {
  1130.         *ptr = 0;
  1131.  
  1132.         if (length != strlen (string)+1)
  1133.         {
  1134.         D(bug("Fehler: length: %ld  strlen: %ld\n",
  1135.             length, strlen(string)+1));
  1136.         }
  1137.     }
  1138.     }
  1139.     else
  1140.     string = NULL;
  1141.  
  1142.     return (string);
  1143. } /* block_to_string */
  1144.  
  1145.  
  1146. /***************************
  1147. ***  TML EDITS STOP HERE  **
  1148. ****************************/
  1149.  
  1150. /*****************************************************************************
  1151.  
  1152.     NAME
  1153.     do_bdelete
  1154.  
  1155.     PARAMETER
  1156.     void
  1157.  
  1158.     RETURN
  1159.     void
  1160.  
  1161.     DESCRIPTION
  1162.     Deletes the marked block from the text.
  1163.  
  1164. ******************************************************************************/
  1165.  
  1166. /*DEFHELP #cmd block BDELETE - delete currently marked text */
  1167.  
  1168. DEFUSERCMD("bdelete", 0, 0, void, do_bdelete, (void),)
  1169. {
  1170.     long lines;
  1171.     ED * bep     = ActualBlock.ep;
  1172.     ED * saveed  = Ep;
  1173.  
  1174.     /* is there a valid block ? */
  1175.     if (!block_ok ())
  1176.     return;
  1177.  
  1178.     /* TODO */
  1179.     if (ActualBlock.type != BT_LINE)
  1180.     {
  1181.     error ("bdelete:\nCannot use for this\ntype of block.");
  1182.     return;
  1183.     }
  1184.  
  1185.     /* don't allow it in VIEWMODE */
  1186.  
  1187.     if (GETF_VIEWMODE(bep))
  1188.     {
  1189.     error ("%s:\nCannot delete from a\nwrite-protected text", av[0]);
  1190.     return;
  1191.     } /* if */
  1192.  
  1193.     /* change editor */
  1194.  
  1195.     switch_ed (bep);
  1196.  
  1197.     /* length of block */
  1198.  
  1199.     lines = ActualBlock.end_line - ActualBlock.start_line + 1;
  1200.  
  1201.     /* if line is inside the block, move to start of block. If it is
  1202.     beyond the end-line, move up */
  1203.  
  1204.     if (bep->line >= ActualBlock.start_line && bep->line <= ActualBlock.end_line)
  1205.     bep->line = ActualBlock.start_line;
  1206.     else if (bep->line > ActualBlock.end_line)
  1207.     bep->line -= lines;
  1208.  
  1209.     /* same for the 1st line */
  1210.  
  1211.     if (bep->topline >= ActualBlock.start_line && bep->topline <= ActualBlock.end_line)
  1212.     bep->topline = ActualBlock.start_line;
  1213.     else if (bep->topline > ActualBlock.end_line)
  1214.     bep->topline -= lines;
  1215.  
  1216.     /* free memory and copy lines from beyond the block back */
  1217.     freelist (bep->list + ActualBlock.start_line, lines);
  1218.     bmovl (bep->list + ActualBlock.end_line + 1,
  1219.         bep->list + ActualBlock.start_line,
  1220.         bep->lines - ActualBlock.end_line - 1);
  1221.  
  1222.     /* adjust number of lines. Text has been modified */
  1223.     bep->lines     -= lines;
  1224.  
  1225.     SETF_MODIFIED(bep, 1);
  1226.  
  1227.     /* move cursor if it's now outside the text */
  1228.     if (bep->line >= bep->lines)
  1229.     bep->line = bep->lines - 1;
  1230.  
  1231.     /* move topline if it's now outside the text */
  1232.     if (bep->topline >= bep->lines)
  1233.     bep->topline = bep->lines - 1;
  1234.  
  1235.     /* no lines in text ? */
  1236.     if (bep->line < 0)
  1237.     bep->topline = bep->line = 0;
  1238.  
  1239.     /* create at least one line */
  1240.  
  1241.     if (bep->lines == 0)
  1242.     {
  1243.     bep->lines ++;
  1244.     SETLINE(bep,0,allocline(1));
  1245.     }
  1246.  
  1247.     /* get current line */
  1248.     text_load ();
  1249.  
  1250.     /* no block anymore */
  1251.     unblock ();
  1252.  
  1253.     /* always redisplay */
  1254.     text_adjust (TRUE);
  1255.  
  1256.     /* adjust scroller */
  1257.     prop_adj ();
  1258.  
  1259.     /* old editor */
  1260.     switch_ed (saveed);
  1261. } /* do_bdelete */
  1262.  
  1263.  
  1264. /*****************************************************************************
  1265.  
  1266.     NAME
  1267.     do_bcopy
  1268.  
  1269.     PARAMETER
  1270.     void
  1271.  
  1272.     RETURN
  1273.     void
  1274.  
  1275.     DESCRIPTION
  1276.     Copies a block to the line above the cursor. It is possible to
  1277.     copy the block into itself thus making it bigger.
  1278.  
  1279. ******************************************************************************/
  1280.  
  1281. /*DEFHELP #cmd block BCOPY - insert currently marked text before cursor */
  1282.  
  1283. DEFUSERCMD("bcopy", 0, CF_BLK|0, void, do_bcopy, (void),)
  1284. {
  1285.     LINE  * list;
  1286.     long    lines,
  1287.         i;
  1288.     ED      * ep = Ep;
  1289.     UBYTE * str;
  1290.  
  1291.     /* update line */
  1292.  
  1293.     text_sync ();
  1294.  
  1295.     /* No valid block ? */
  1296.     if (!block_ok ())
  1297.     return;
  1298.  
  1299.     /* TODO */
  1300.     if (ActualBlock.type != BT_LINE)
  1301.     {
  1302.     error ("bcopy:\nCannot use for this\ntype of block.");
  1303.     return;
  1304.     }
  1305.  
  1306.     /* get length of block */
  1307.  
  1308.     lines = ActualBlock.end_line - ActualBlock.start_line + 1;
  1309.  
  1310.     /* make sure we have enough space */
  1311.  
  1312.     if (extend (ep, lines))
  1313.     {
  1314.     /* get memory for lines */
  1315.  
  1316.     if ((list = (LINE *)alloclptr(lines)))
  1317.     {
  1318.         /* copy lines to buffer */
  1319.  
  1320.         bmovl (ActualBlock.ep->list+ActualBlock.start_line, list, lines);
  1321.  
  1322.         /* make room for the lines */
  1323.  
  1324.         bmovl (ep->list+ep->line, ep->list+ep->line+lines,
  1325.             ep->lines-ep->line);
  1326.  
  1327.         /* now copy each separate line */
  1328.  
  1329.         for (i = 0; i < lines; i ++)
  1330.         {
  1331.         /* get memory for one line */
  1332.  
  1333.         str = allocline (LENGTH ((char *)list[i]) + 1);
  1334.  
  1335.         /* no more memory ? */
  1336.  
  1337.         if (!str)
  1338.         {
  1339.             /* set error */
  1340.  
  1341.             nomemory ();
  1342.  
  1343.             /* free memory */
  1344.  
  1345.             FreeMem (list, lines * sizeof(LINE));
  1346.             freelist (ep->list + ep->line, i);
  1347.  
  1348.             /* make space for block disappear */
  1349.  
  1350.             bmovl (ep->list+ep->line+lines, ep->list+ep->line,
  1351.                 ep->lines-ep->line);
  1352.  
  1353.             return;
  1354.         }
  1355.  
  1356.         /* copy contents */
  1357.  
  1358.         strcpy ((char *)str, (char *)list[i]);
  1359.  
  1360.         /* add line to list */
  1361.  
  1362.         SETLINE(ep,ep->line+i,str);
  1363.         }
  1364.  
  1365.         /* free buffer */
  1366.  
  1367.         FreeMem (list, lines * sizeof(LINE));
  1368.  
  1369.         /* if we inserted the block before the start of the block,
  1370.            we must adjust it */
  1371.  
  1372.         if (ep == ActualBlock.ep)
  1373.         {
  1374.         if (ep->line <= ActualBlock.start_line)
  1375.         {
  1376.             ActualBlock.start_line += lines;
  1377.             ActualBlock.end_line   += lines;
  1378.         } else if (ep->line <= ActualBlock.end_line)
  1379.             ActualBlock.end_line   += lines;
  1380.         }
  1381.  
  1382.         /* Text has been modified. Also the number of lines has changed. */
  1383.  
  1384.         SETF_MODIFIED(ep, 1);
  1385.         ep->lines += lines;
  1386.  
  1387. #ifdef NOTDEF
  1388.         /* update display */
  1389.         if (!text_adjust (FALSE))
  1390.         {
  1391.         scroll_display (0, -lines, ep->topcolumn, ep->line,
  1392.             ep->topcolumn+Columns, ep->topline+Lines);
  1393.         }
  1394. #endif
  1395.  
  1396.         /* Move cursor to the bottom */
  1397.  
  1398.         ep->line += lines;
  1399.  
  1400.         /* get new contents */
  1401.  
  1402.         text_load ();
  1403.  
  1404.         if (!text_adjust (FALSE)) /* display is adjusted, if needed */
  1405.         {
  1406.         scroll_display (0, -lines, ep->topcolumn, ep->line-lines,
  1407.             ep->topcolumn+Columns, ep->topline+Lines-1);
  1408.         }
  1409.  
  1410.         /* adjust scroller */
  1411.         prop_adj ();
  1412.     } else
  1413.         nomemory ();
  1414.     } else
  1415.     nomemory ();
  1416. } /* do_bcopy */
  1417.  
  1418.  
  1419. /*****************************************************************************
  1420.  
  1421.     NAME
  1422.     do_bmove
  1423.  
  1424.     PARAMETER
  1425.     void
  1426.  
  1427.     RETURN
  1428.     void
  1429.  
  1430.     DESCRIPTION
  1431.     Moves the marked block between the current line and the line
  1432.     above it. It's not possible to move the block into itself.
  1433.  
  1434. ******************************************************************************/
  1435.  
  1436. /*DEFHELP #cmd block BMOVE - delete currently marked text and insert it before cursor line */
  1437.  
  1438. DEFUSERCMD("bmove", 0, CF_BLK|0, void, do_bmove, (void),)
  1439. {
  1440.     long   lines;
  1441.     LINE * list;
  1442.     ED     * ep = Ep;
  1443.  
  1444.     /* update text */
  1445.  
  1446.     text_sync ();
  1447.  
  1448.     /* no block ?? */
  1449.     if (!block_ok ())
  1450.     return;
  1451.  
  1452.     /* TODO */
  1453.     if (ActualBlock.type != BT_LINE)
  1454.     {
  1455.     error ("bmove:\nCannot use for this\ntype of block.");
  1456.     return;
  1457.     }
  1458.  
  1459.     /* not allowed in viewmode */
  1460.  
  1461.     if (GETF_VIEWMODE(ActualBlock.ep))
  1462.     {
  1463.     error ("%s:\nCannot move from a\nwrite-protected text", av[0]);
  1464.     return;
  1465.     } /* if */
  1466.  
  1467.     /* it is not very usefull to move a block into itself */
  1468.  
  1469.     if (    ActualBlock.ep == ep                &&
  1470.         ep->line >= ActualBlock.start_line    &&
  1471.         ep->line <= ActualBlock.end_line    )
  1472.     {
  1473.     error ("bmove:\nCannot move a\nblock into itself");
  1474.     return;
  1475.     }
  1476.  
  1477.     /* length of block */
  1478.  
  1479.     lines = ActualBlock.end_line - ActualBlock.start_line + 1;
  1480.  
  1481.     /* get memory for a copy of the block */
  1482.  
  1483.     if (!(list = (LINE *)alloclptr (lines)))
  1484.     {
  1485.     nomemory ();
  1486.     return;
  1487.     }
  1488.  
  1489.     /* text has been modified */
  1490.     SETF_MODIFIED (ActualBlock.ep, 1);
  1491.     SETF_MODIFIED (ep, 1);
  1492.  
  1493.     /* copy block to tmp. memory */
  1494.     bmovl (ActualBlock.ep->list + ActualBlock.start_line, list, lines);
  1495.  
  1496.     /* are we in the editor that has the block or do we have to move the
  1497.        block to some other editor ? */
  1498.     if (ep == ActualBlock.ep)
  1499.     {
  1500.     /* behind the block: move the lines behind the block upto the current
  1501.        line up to the line where the block started and copy the former
  1502.        block into the new space */
  1503.  
  1504.     if (ep->line > ActualBlock.start_line)
  1505.     {
  1506.         bmovl ( ep->list + ActualBlock.end_line + 1,
  1507.             ep->list + ActualBlock.start_line,
  1508.             ep->line - ActualBlock.end_line -1);
  1509.         bmovl (list, ep->list + ep->line - lines, lines);
  1510.     } else
  1511.     {   /* before the block: copy all lines from the current upto
  1512.            the line where the block began up to the block-end
  1513.            and copy the former block into the new space */
  1514.  
  1515.         bmovl (ep->list + ep->line, ep->list + ep->line + lines,
  1516.             ActualBlock.start_line - ep->line);
  1517.         bmovl (list, ep->list + ep->line, lines);
  1518.  
  1519.         /* move down */
  1520.         ep->line += lines;
  1521.     }
  1522.  
  1523.     /* load (new) current line */
  1524.     text_load ();
  1525.     } else
  1526.     {    /* move block between editors */
  1527.  
  1528.     /* make room in the editor that gets the block */
  1529.     if (extend (ep, lines))
  1530.     {
  1531.         /* copy the lines after the block the beginning of the block
  1532.            thus deleting him */
  1533.  
  1534.         bmovl ( ActualBlock.ep->list + ActualBlock.end_line + 1,
  1535.             ActualBlock.ep->list + ActualBlock.start_line,
  1536.             ActualBlock.ep->lines - ActualBlock.end_line - 1);
  1537.  
  1538.         /* make room in the list of lines for the block */
  1539.         bmovl ( ep->list + ep->line,
  1540.             ep->list + ep->line + lines,
  1541.             ep->lines - ep->line);
  1542.  
  1543.         /* copy the buffer to its new place */
  1544.         bmovl (list, ep->list + ep->line, lines);
  1545.  
  1546.         /* adjust the number of lines both editors have now */
  1547.         ep->lines          += lines; /* he gets the block */
  1548.         ActualBlock.ep->lines -= lines; /* he lost it */
  1549.  
  1550.         /* the current line in the editor that had the block was inside
  1551.            the block */
  1552.         if (    ActualBlock.ep->line >= ActualBlock.start_line  &&
  1553.             ActualBlock.ep->line <= ActualBlock.end_line    )
  1554.         {
  1555.         /* move cursor to the place where the block started */
  1556.         ActualBlock.ep->line = ActualBlock.start_line;
  1557.  
  1558.         /* if the block was the last thing in this text, move up
  1559.            one more line */
  1560.         if (ActualBlock.ep->line == ActualBlock.ep->lines)
  1561.             ActualBlock.ep->line --;
  1562.         }
  1563.  
  1564.         /* if the line was behind the last line of the block, move up
  1565.            the length of the block in lines. */
  1566.         if (ActualBlock.ep->line > ActualBlock.end_line)
  1567.         ActualBlock.ep->line -= lines;
  1568.  
  1569.         /* ... but not too far */
  1570.         if (ActualBlock.ep->line < 0)
  1571.         ActualBlock.ep->line = 0;
  1572.  
  1573.         /* if we moved the whole text, make sure the old editor
  1574.            al least contains one single line */
  1575.         if (ActualBlock.ep->lines == 0)
  1576.         {
  1577.         LINE ptr = allocline (1);
  1578.  
  1579.         SETLINE(ActualBlock.ep,0,ptr);
  1580.         ActualBlock.ep->lines ++;
  1581.         }
  1582.  
  1583.         ep->line += lines;    /* Move cursor down */
  1584.  
  1585.         ActualBlock.type = BT_NONE; /* clear block */
  1586.  
  1587.         text_load ();       /* text_switch() calls text_sync() ! */
  1588.         switch_ed (ActualBlock.ep); /* make source to the active editor */
  1589.  
  1590.         if (!GETF_ICONMODE(Ep))
  1591.         {         /* Not iconified */
  1592.         text_adjust (TRUE);
  1593.  
  1594.         /* adjust scroller */
  1595.         prop_adj ();
  1596.         }
  1597.  
  1598.         switch_ed (ep);             /* old Ed */
  1599.     }
  1600.     }
  1601.  
  1602.     unblock ();                         /* We don't have any block anymore */
  1603.  
  1604.     /* free tmp. buffer */
  1605.     FreeMem (list, lines * sizeof(LINE));
  1606.  
  1607.     /* force redisplay */
  1608.     text_adjust (TRUE);
  1609. } /* do_bmove */
  1610.  
  1611.  
  1612. /*****************************************************************************
  1613.  
  1614.     NAME
  1615.     do_bsource
  1616.  
  1617.     PARAMETER
  1618.     void
  1619.  
  1620.     RETURN
  1621.     void
  1622.  
  1623.     DESCRIPTION
  1624.     Executes all lines inside a block as if they were typed as commands.
  1625.     The block is removed before the execution starts. The text
  1626.     is updated before every line. Thus self-modifying code is possible.
  1627.  
  1628.     NOTE
  1629.     - since the start and end lines are loaded immediately and the
  1630.       block unblock'd before execution starts, you can theoretically have
  1631.       another BSOURCE as part of this BSOURCE (but be carefull!).
  1632.     - BSOURCE allows self-modifying code
  1633.  
  1634. ******************************************************************************/
  1635.  
  1636. /*DEFHELP #cmd block,source BSOURCE - execute currently marked text block as if it were a script file */
  1637.  
  1638. DEFUSERCMD("bsource", 0, CF_VWM|CF_ICO, void, do_bsource, (void),)
  1639. {
  1640.     ED * ep;
  1641.     char buf[MAXLINELEN];
  1642.     int  i, start, end;
  1643.  
  1644.     if (!block_ok ())
  1645.     return;
  1646.  
  1647.     /* TODO */
  1648.     if (ActualBlock.type != BT_LINE)
  1649.     {
  1650.     error ("bsource:\nCannot use for this\ntype of block.");
  1651.     return;
  1652.     }
  1653.  
  1654.     /* find start and end */
  1655.  
  1656.     ep      = ActualBlock.ep;
  1657.     start = ActualBlock.start_line;
  1658.     end   = ActualBlock.end_line + 1;
  1659.  
  1660.     /* unblock */
  1661.  
  1662.     text_redrawblock (0);
  1663.  
  1664.     /* execute every line */
  1665.  
  1666.     for (i = start; i < end; i ++)
  1667.     {
  1668.     text_sync (); /* make sure we are using the latest text */
  1669.  
  1670.     if (*(GETTEXT(ep,i)) != '#')
  1671.     {
  1672.         strcpy (buf, GETTEXT(ep,i));
  1673.  
  1674.         if (!do_command (buf))
  1675.         break;
  1676.     }
  1677.     }
  1678. } /* do_bsource */
  1679.  
  1680.  
  1681. /******************************************************************************
  1682. *****  ENDE block.c
  1683. ******************************************************************************/
  1684.